home *** CD-ROM | disk | FTP | other *** search
- /*
- GDTimeClut.c
-
- error=GDTimeClut(device,GDSetEntries,clutEntries,&s,&frames,&missingFrames,&frameRate);
-
- GDTimeClut measures how long it takes to load the clut. It measures in two kinds
- of units simultaneously, frames and seconds. You supply the function to be
- tested, e.g. SetEntriesQuickly or GDSetEntries. (If mode>eightBitMode GDTimeClut
- will automatically substitute GDDirectSetEntries for GDSetEntries.) The second
- argument, "clutEntries", specifies how many clut entries you want to update each
- time, or zero for all, e.g. all 256 in 8-bit mode. It also measures the frame
- rate independently, which it returns, after using it to estimate how many frame
- interrupts were missed during each clut load. If there's at least one frame
- missing or if the frame count is very small, less than 0.5 per call, then it
- estimates the frames directly from the time. You may substitute NULL for any of
- the pointer-to-double arguments.
-
- Use GDTimeClut() instead of the old functions, GDFramesPerClutUpdate,
- GDClutUpdateRate, and GDTimeClutUpdate in GDFrameRate.c. They are now obsolete.
-
- It is of interest to time GDSetEntries (and its sibling GDDirectSetEntries) at
- both normal (zero) and high (7) processor interrupt priority, because some
- drivers are asynchronous when run at low priority, returning immediately and
- deferring the actual clut loading until the vbl interrupt occurs, but Apple
- specifies that all drivers must be synchronous when run at high priority. You do
- this by supplying the new routine GDSetEntriesByTypeHighPriority().
-
- Similarly, while the problem of multiple interrupts per frame is dealt with
- satisfactorily by VBLInstall.c, using the scheme suggested by Raynald Comtois,
- it is of technical interest to follow up the report that there are no extra
- interrupts if the processor instruction cache is disabled. One theory to account
- for this is that perhaps disabling the cache causes the interrupt service
- routine to take long enough that the hardware interrupt pulse has terminated
- before the routine exits. Thus I would like to write a routine called
- GDSetEntriesNoCache, but I don't know how to disable the cache.
-
- HISTORY:
- 3/11/93 dgp created it, based on GDTimeClutUpdate and GDFramesPerClutUpdate in
- GDFrameRate.c. The enhancements are 1. you supply the function to be tested,
- either SetEntriesQuickly or GDSetEntries. 2. It doesn't print or exit, always
- returning with an informative OSErr. 3. It measures frame rate independently,
- which it returns, and also uses it to estimate how many frame interrupts were
- missed during each clut load. 4. If there's at least one frame missing or if the
- frame count is very small, less than 0.5 per call, then it estimates the frames
- directly from the time.
-
- */
- #include <VideoToolbox.h>
- #include <math.h>
- #define CALLS 30
- // Original typedef is in VideoToolbox.h
- //typedef OSErr (*SetEntriesFunction)(GDHandle device,short start,short count
- // ,ColorSpec *aTable);
-
- OSErr GDTimeClut(GDHandle device,SetEntriesFunction function,short clutEntries
- ,double *sPtr,double *framesPtr,double *missingFramesPtr,double *frameRatePtr)
- {
- OSErr error;
- short mode,clutSize,i;
- ColorSpec *table,*linearTable=NULL;
- static VBLTaskAndA5 vblData;
- long frames;
- Timer *timer;
- double s,missingFrames,frameRate;
-
- if(sPtr!=NULL)*sPtr=NAN;
- if(framesPtr!=NULL)*framesPtr=NAN;
- if(missingFramesPtr!=NULL)*missingFramesPtr=NAN;
- if(frameRatePtr!=NULL)*frameRatePtr=NAN;
- clutSize=GDClutSize(device);
- if(clutEntries<0 || clutEntries>clutSize)return 1;
- if(clutEntries==0)clutEntries=clutSize;
- error=GDGetMode(device,&mode,NULL,NULL);
- if(error)mode=(**device).gdMode;
- if(mode>eightBitMode){
- if(function==GDSetEntries)function=GDDirectSetEntries;
- table=linearTable=(ColorSpec *)NewPtr(clutSize*sizeof(linearTable[0]));
- if(linearTable==NULL)return MemError();
- for(i=0;i<clutSize;i++){
- table->rgb.red=table->rgb.green=table->rgb.blue=(long)0xffff*i/(clutSize-1);
- table++;
- }
- }else table=((**(**(**device).gdPMap).pmTable)).ctTable;
- vblData.subroutine=NULL; // setup frame counter
- error=VBLInstall(&vblData,device,CALLS*20); // setup frame counter
- if(error)return error;
- timer=NewTimer(); // setup timer
- if(timer==NULL)return 1; // lacks Revised Time Manager.
- vblData.vbl.vblCount=1; // Enable interrupt service routine
- for(i=-1;i<CALLS;i++) {
- error=(function)(device,0,clutEntries-1,table);
- if(i==-1){
- StartTimer(timer);
- frames=vblData.framesLeft;
- }
- if(error)break;
- }
- frames-=vblData.framesLeft;
- s=StopTimerSecs(timer);
- VBLRemove(&vblData);
- DisposeTimer(timer);
- if(linearTable!=NULL)DisposePtr((Ptr)linearTable);
- if(error)return error;
-
- // Estimate number of missing frames by discrepancy between frames and secs.
- frameRate=GDFrameRate(device);
- missingFrames=s*frameRate-frames;
-
- // Return results
- if(sPtr!=NULL)*sPtr=s/CALLS;
- if(framesPtr!=NULL){
- if(fabs(missingFrames)>1. || frames<CALLS/2) *framesPtr=frameRate*s/CALLS;
- else *framesPtr=frames/(double)CALLS;
- }
- if(missingFramesPtr!=NULL)*missingFramesPtr=missingFrames/CALLS;
- if(frameRatePtr!=NULL)*frameRatePtr=frameRate;
- return 0;
- }
-